import motor.motor_asyncio
import asyncio

class Mongo:
    def __init__(self, host='localhost', user=None, passwd=None, port=27017, db='tingdan'):
        if user:
            connection_str = 'mongodb://{}:{}@{}:{}/{}'.format(user, passwd, host, port, db)
        else:
            connection_str = 'mongodb://{}:{}/{}'.format(host, port, db)
        self.client = motor.motor_asyncio.AsyncIOMotorClient(connection_str)
        self.conn = self.client[db]

    async def insert_one(self, data):
        assert(type(data) != list)  # only one line can be inserted
        collection = self.conn['tingdan']
        object_id = await collection.insert(data)
        res = await collection.find_one({'_id': object_id})
        return res

    async def insert_many(self, data):
        assert(type(data) == list)  # should be a list
        collection = self.conn['tingdan']
        object_ids = await collection.insert(data)
        res = await self.find({'_id': {'$in': object_ids}}, limit=None)
        return res

    async def find(self, stat, skip=0, limit=100, sort=None):
        # sort : [(field, pymongo.DESCENDING)]
        collection = self.conn['tingdan']
        cur = collection.find(stat)
        if sort:
            cur = cur.sort(sort)
        cur = cur.skip(skip)
        result = await cur.to_list(length=limit)
        return result

    async def exists(self, stat):
        collection = self.conn['tingdan']
        res = await collection.find_one(stat)
        if res is None:
            return False
        else:
            return True

    async def update_one(self, stat, data):
        collection = self.conn['tingdan']
        old_document = await collection.find_one(stat)
        _id = old_document['_id']
        await collection.update({'_id': _id}, data, multi=False)
        new_document = await collection.find_one({'_id': _id})
        return new_document

if __name__ == '__main__':
    m = Mongo()
    loop = asyncio.get_event_loop()
    print(loop.run_until_complete(m.find({}, skip=1, limit=2)))
    loop.close()
